package com.xm.common.oss

import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider
import com.alibaba.sdk.android.oss.ClientConfiguration
import com.alibaba.sdk.android.oss.OSSClient
import com.alibaba.sdk.android.oss.model.PutObjectRequest
import com.alibaba.sdk.android.oss.callback.OSSProgressCallback
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback
import com.alibaba.sdk.android.oss.model.PutObjectResult
import com.alibaba.sdk.android.oss.ClientException
import com.alibaba.sdk.android.oss.ServiceException
import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.alibaba.sdk.android.oss.common.OSSLog
import java.io.File

/**
 * OSS上传工具类
 */
object OssHelper {

    /**
     * 异步上传文件
     */
    fun asyncUpload(
        context: Context?,//上下文，避免内存泄漏，最好使用 applicationContext
        accessKeyId: String?,//服务端返回
        accessKeySecret: String?,//服务端返回
        bucketName: String?,//服务端返回
        endPoint: String?,//服务端返回
        securityToken: String?,//服务端返回
        dir: String?,//服务端返回
        fileName: String?,//服务端返回
        path: String?,//文件路径
        progressLiveData: MutableLiveData<Progress>?,//进度回调
        successLiveData: MutableLiveData<String>?,//成功回调
        failureLiveData: MutableLiveData<Error>?,//失败回调
    ) {
        //开启日志
        OSSLog.enableLog()
        //凭证提供者
        val credentialProvider: OSSCredentialProvider =
            OSSStsTokenCredentialProvider(accessKeyId, accessKeySecret, securityToken)
        //请求配置
        val config = ClientConfiguration()
        config.connectionTimeout = 15 * 1000 // 连接超时
        config.socketTimeout = 15 * 1000 // socket超时
        config.maxConcurrentRequest = 5 // 最大并发请求数
        config.maxErrorRetry = 2 //失败后最大重试次数
        val client = OSSClient(context, endPoint, credentialProvider, config)

        //图片在服务器上的相对路径
        val objectKey = dir + File.separator + fileName + ".jpg"
        //请求对象
        val request = PutObjectRequest(bucketName, objectKey, path)

        //监听进度
        request.progressCallback = OSSProgressCallback { request, currentSize, totalSize ->
            progressLiveData?.postValue(Progress(currentSize, totalSize))
        }

        //异步请求
        client.asyncPutObject(
            request,
            object : OSSCompletedCallback<PutObjectRequest?, PutObjectResult?> {

                override fun onSuccess(request: PutObjectRequest?, result: PutObjectResult?) {
                    successLiveData?.postValue("http://" + bucketName + "." + endPoint + File.separator + dir + File.separator + fileName + ".jpg")
                }

                override fun onFailure(
                    request: PutObjectRequest?,
                    clientException: ClientException,
                    serviceException: ServiceException
                ) {
                    failureLiveData?.postValue(OssHelper.Error(clientException, serviceException))
                }
            })
    }

    /**
     * 同步上传
     */
    suspend fun syncUpload(
        context: Context?,//上下文，避免内存泄漏，最好使用 applicationContext
        accessKeyId: String?,//服务端返回
        accessKeySecret: String?,//服务端返回
        bucketName: String?,//服务端返回
        endPoint: String?,//服务端返回
        securityToken: String?,//服务端返回
        dir: String?,//服务端返回
        fileName: String?,//服务端返回
        path: String?,//文件路径
    ): String {
        //开启日志
        OSSLog.enableLog()
        //凭证提供者
        val credentialProvider: OSSCredentialProvider =
            OSSStsTokenCredentialProvider(accessKeyId, accessKeySecret, securityToken)
        //请求配置
        val config = ClientConfiguration()
        config.connectionTimeout = 15 * 1000 // 连接超时
        config.socketTimeout = 15 * 1000 // socket超时
        config.maxConcurrentRequest = 5 // 最大并发请求数
        config.maxErrorRetry = 2 //失败后最大重试次数
        val client = OSSClient(context, endPoint, credentialProvider, config)

        //图片在服务器上的相对路径
        val objectKey = dir + File.separator + fileName + ".jpg"
        //请求对象
        val request = PutObjectRequest(
            bucketName,
            objectKey,
            path
        )
        //同步上传
        client.putObject(request)
        return "http://" + bucketName + "." + endPoint + File.separator + dir + File.separator + fileName + ".jpg"
    }

    class Progress(var currentSize: Long, var totalSize: Long)

    class Error(var clientException: ClientException, var serviceException: ServiceException)
}